﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DTO;
using ModelAccess.Concrete;
using ModelLayer;
using log4net;
using BusinessLayer.Logic.UserLogic;

namespace BusinessLayer
{
    public class ProfiloLogic
    {
        private static readonly ILog log = LogManager.GetLogger(
                 System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public UtenteProfiliDTO calcolaProfili(DTOUtente utenteDTO,bool withRisposte)
        {
            List<ProfiliDTO> listaProfili = new List<ProfiliDTO>();
            using (UtentiHelper uh = new UtentiHelper())
            {
                Utente u = uh.getRisposteUtente(utenteDTO.Username);
                if (withRisposte)
                {
                    utenteDTO.Risposte=new List<RispostaDTO>();
                    foreach (Risposta r in u.Risposte)
                    { 
                        String competenzaS=r.AnagraficaPesi.Competenza.Codice;
                        int rispostaS= r.AnagraficaPesi.AnagraficaRisposta.Id;
                        utenteDTO.Risposte.Add(new RispostaDTO() { competenza = competenzaS, riposta = rispostaS });

                    }
                
                }
                ProfiloHelper ph = new ProfiloHelper(uh);
                List<Profilo> profili = ph.getProfile();
                foreach (Profilo prof in profili)
                {
                    listaProfili.Add(calcolaProfilo(u, prof));
                }

            }
            return new UtenteProfiliDTO() { profili=listaProfili,utente=utenteDTO};
        
        }

       
        private ProfiloCompetenzaDTO createProfiloCompetenza(Competenza comp,ProfiliDTO profileDto)
        {
            Competenza copyComp = copiaCompetenza(comp);
            ProfiloCompetenzaDTO dto = new ProfiloCompetenzaDTO();
            dto.Competenza = copyComp;
            dto.PesoCompetenza = comp.AnagraficaPesi[0].Peso;
            
            return dto;
        }

        private Competenza copiaCompetenza(Competenza comp)
        {
            Competenza copyComp = new Competenza() { Id = comp.Id, Codice = comp.Codice }.MarkAsUnchanged();
            return copyComp;
        }

        public ProfiliDTO calcolaProfilo(Utente u, Profilo prof)
        {
            ProfiliDTO dto = new ProfiliDTO();
            double percentuale = 0;
            double sommaPercentualeNumeratore=0;
            double sommaPercentualeDenominatore = 0;


            Dictionary<String, ProfiloCompetenzaDTO> dtoCompetenze = new Dictionary<string, ProfiloCompetenzaDTO>();
            
            /*100 *( 1- ( SUM( max( Ri-Pi , 0 )^2 ) )  / SUM(Ri^2) )*/
            foreach(AnagraficaPesi peso in prof.AnagraficaPesi)
            {
                AnagraficaPesi pesoUtente=peso.Competenza.AnagraficaPesi.Where(x => x.Risposta.Count > 0).Single();
                double diffPesi=peso.Peso-(pesoUtente.Peso>0?pesoUtente.Peso:0);
                if( diffPesi<0) diffPesi=0;
                sommaPercentualeNumeratore += Math.Pow(diffPesi, 2);
                sommaPercentualeDenominatore += Math.Pow(peso.Peso, 2);
                ProfiloCompetenzaDTO compDTO;
                if (dtoCompetenze.ContainsKey(peso.Competenza.Padre.Codice))
                {
                    compDTO = dtoCompetenze[peso.Competenza.Padre.Codice];
                }
                else
                {
                    compDTO = createProfiloCompetenza(peso.Competenza.Padre,dto);
                    dtoCompetenze.Add(compDTO.Competenza.Codice,compDTO);
                    
                }
                compDTO.Richiesto += peso.Peso;

                if (pesoUtente.Peso < peso.Peso)
                {
                    if (pesoUtente.Peso > 0)
                    {
                        compDTO.CompetenzeMancantiMaSufficenti.Add(copiaCompetenza(peso.Competenza));
                    }
                    else
                    {
                        compDTO.CompetenzeMancanti.Add(copiaCompetenza(peso.Competenza));
                    }
                }
                if (pesoUtente.Peso > peso.Peso)
                {
                    compDTO.CompetenzeInPiu.Add(copiaCompetenza(peso.Competenza));
                }
            }
            
            percentuale = 100 * (1 - (sommaPercentualeNumeratore/sommaPercentualeDenominatore));

            foreach (Risposta r in u.Risposte)
            {
                AnagraficaPesi peso = r.AnagraficaPesi;
                ProfiloCompetenzaDTO compDTO;
                if (dtoCompetenze.ContainsKey(peso.Competenza.Padre.Codice))
                {
                    compDTO = dtoCompetenze[peso.Competenza.Padre.Codice];
                    
                }
                else 
                {
                    compDTO = createProfiloCompetenza(peso.Competenza.Padre, dto);
                    compDTO.Richiesto = 0;
                    dtoCompetenze.Add(compDTO.Competenza.Codice, compDTO);
                }
                compDTO.Fornito += peso.Peso;
            }


            foreach (ProfiloCompetenzaDTO profDto in dtoCompetenze.Values)
            {

                if (profDto.Richiesto == 0)
                {
                    profDto.Richiesto = 4;
                }
                else
                {
                    profDto.Richiesto = 4 + 2.34 * Math.Log(1 + (profDto.Richiesto / profDto.PesoCompetenza));
                }
                profDto.Fornito = 4 + 2.34 * Math.Log(1 + (profDto.Fornito / profDto.PesoCompetenza));
                //log.Info("Competenza " + profDto.Competenza.Codice + " richiesto:" + profDto.Richiesto + " fornito" + profDto.Fornito);
            }
            dto.Competenze = dtoCompetenze.Values.OrderBy(x => x.Competenza.Id).ToList();
            dto.NomeProfilo = prof.Nome;
            dto.PercentualeProssimita = percentuale;
            return dto;
        }




        public List<UtenteProfiliDTO> calcolaProfili(List<DTOUtente> utenti,bool withRisposte)
        {
            List<UtenteProfiliDTO> utenteProfili = new List<UtenteProfiliDTO>();
            foreach (DTOUtente utente in utenti)
            {

                UtenteProfiliDTO up = calcolaProfili(utente, withRisposte);
                utenteProfili.Add(up);
            }
            return utenteProfili;
        }
    }
}
